package matheus.tp01cg.objetosdedesenho;

import java.util.ArrayList;

import android.graphics.Bitmap;
import android.util.Log;

/**
 * Classe base para desenhos de poligonos. Armazena uma lista de vertices
 * 
 * @author matheus
 * 
 */
public abstract class Poligono extends ObjetoDeDesenhoFechado {
	private boolean fechado;

	public boolean isFechado() {
		return fechado;
	}

	/**
	 * Lista dos vertices do poligono
	 */
	public ArrayList<Coords> listaDeVertices = new ArrayList<Coords>();

	/**
	 * Conecta o ultimo vertice ao primeiro adicionado
	 */
	public void fechar() throws Exception {
		if (listaDeVertices.size() > 0)
			fechado = true;
		else
			throw new Exception("Impossivel fechar poligo vazio");
	}

	public Poligono(int corBorda, int corPreenchimento) {
		fechado = false;
		setCorContorno(corBorda);
		setCorPreenchimento(corPreenchimento);
	}

	public ArrayList<Coords> getVertices() {
		return listaDeVertices;
	}

	public void adicionarVertice(Coords coords) throws Exception {
		if (!fechado) {
			if (listaDeVertices.size() > 0
					&& coords.equals(listaDeVertices.get(0))) {
				fechado = true;
			} else {
				listaDeVertices.add(coords);
			}
		} else {
			throw new Exception("Poligono esta fechado");
		}
	}

	@Override
	public void desenha(Bitmap bitmap) {
		ArrayList<Reta> listaDeRetas = criarListaDeRetas();
		for (int i = 0; i < listaDeRetas.size(); i++) {
			listaDeRetas.get(i).desenha(bitmap);
		}
	}

	/**
	 * Cria uma reta baseada no algoritmo implementado na subclasse
	 */
	public abstract Reta retaCreate(Coords pontoInicial, Coords pontoFinal,
			int cor);

	/**
	 * Obtem um lista de retas referente ao poligono
	 */
	public ArrayList<Reta> criarListaDeRetas() {
		ArrayList<Reta> listaDeRetas = new ArrayList<Reta>();
		Reta reta;
		for (int i = 0; i < (listaDeVertices.size() - 1); i++) {
			reta = retaCreate(listaDeVertices.get(i),
					listaDeVertices.get(i + 1), corContorno);
			reta.espessuraBorda = espessuraBorda;
			listaDeRetas.add(reta);
		}
		if (isFechado() && listaDeVertices.size() > 0) {
			reta = retaCreate(listaDeVertices.get(listaDeVertices.size() - 1),
					listaDeVertices.get(0), corContorno);
			reta.espessuraBorda = espessuraBorda;
			listaDeRetas.add(reta);
		}
		return listaDeRetas;
	}

	/**
	 * Desenha o ultimo segmento de reta adicionado (util para desenho sendo
	 * realizado interativamente)
	 */
	public void desenhaUltimoSegmento(Bitmap bitmap) {
		if (isFechado()) {
			Reta reta = retaCreate(
					listaDeVertices.get(listaDeVertices.size() - 1),
					listaDeVertices.get(0), corContorno);
			reta.espessuraBorda = espessuraBorda;
			reta.desenha(bitmap);
		} else {
			if (listaDeVertices.size() > 1) {
				Reta reta = retaCreate(
						listaDeVertices.get(listaDeVertices.size() - 2),
						listaDeVertices.get(listaDeVertices.size() - 1),
						corContorno);
				reta.espessuraBorda = espessuraBorda;
				reta.desenha(bitmap);
			}
		}
	}

	@Override
	public int getMinX() {
		int minX = Integer.MAX_VALUE;
		for (int i = 0; i < listaDeVertices.size(); i++) {
			if (listaDeVertices.get(i).x < minX)
				minX = listaDeVertices.get(i).x;
		}
		return minX;
	}

	@Override
	public int getMaxX() {
		int maxX = Integer.MIN_VALUE;
		for (int i = 0; i < listaDeVertices.size(); i++) {
			if (listaDeVertices.get(i).x > maxX)
				maxX = listaDeVertices.get(i).x;
		}
		return maxX;
	}

	@Override
	public int getMinY() {
		int minY = Integer.MAX_VALUE;
		for (int i = 0; i < listaDeVertices.size(); i++) {
			if (listaDeVertices.get(i).y < minY)
				minY = listaDeVertices.get(i).y;
		}
		return minY;
	}

	@Override
	public int getMaxY() {
		int maxY = Integer.MIN_VALUE;
		for (int i = 0; i < listaDeVertices.size(); i++) {
			if (listaDeVertices.get(i).y > maxY)
				maxY = listaDeVertices.get(i).y;
		}
		return maxY;
	}

	@Override
	public void rotaciona(Coords centro, double angulo) {
		for (int i = 0; i < listaDeVertices.size(); i++)
			listaDeVertices.get(i).rotaciona(centro, angulo);
	}

	@Override
	public void translada(int x, int y) {
		for (int i = 0; i < listaDeVertices.size(); i++)
			listaDeVertices.get(i).translada(x, y);
	}

	@Override
	public void escala(Coords ref, double x, double y) {
		for (int i = 0; i < listaDeVertices.size(); i++)
			listaDeVertices.get(i).escala(ref, x, y);
	}

	/**
	 * Cria uma instancia da subclasse concreta de Poligono. O objetivo deste
	 * metodo eh possibilitar a criacao de poligonos mesmo sem conhecer os
	 * detalhes de implementacao (qual algoritmo de reta esta sendo utilizado)
	 */
	public abstract Poligono poligonoCreate(int corBorda, int corPreenchimento);

	@Override
	public Object clone() throws CloneNotSupportedException {
		Poligono novoPoligono = poligonoCreate(corContorno, corPreenchimento);
		for (int i = 0; i < listaDeVertices.size(); i++) {
			try {
				novoPoligono.adicionarVertice((Coords) listaDeVertices.get(i)
						.clone());
			} catch (Exception e) {
				Log.d(null, "Excecao lancada em " + getClass().toString()
						+ ".clone() por novoPoligono.adicionarVertice()", e);
			}
		}
		novoPoligono.fechado = fechado;
		return (Object) novoPoligono;
	}

	@Override
	public boolean intercepta(Coords ponto, int raio) {
		for (int i = 0; i < (listaDeVertices.size() - 1); i++) {
			if (Reta.intercepta(listaDeVertices.get(i),
					listaDeVertices.get(i + 1), ponto, raio)) {
				return true;
			}
		}
		if (isFechado() && listaDeVertices.size() > 0) {
			if (Reta.intercepta(
					listaDeVertices.get(listaDeVertices.size() - 1),
					listaDeVertices.get(0), ponto, raio)) {
				return true;
			}
		}
		return false;
	}
}
